home *** CD-ROM | disk | FTP | other *** search
- /* lgrind.c, a %%\LaTeX%% version of tgrind, which is a %%\TeX%% version
- * of vgrind. Used to `grind nice program listings'.
- */
-
- #ifndef lint
- static char sccsid[] = "@(#)@(#)tfontedpr.c 1.3 (LBL) 4/12/85";
- static char Version[] =
- "$Id: lgrind.c,v 1.4 91/10/01 00:36:11 gvr Exp $";
- #endif
-
- /* lgrind --- general purpose "pretty printer" for use with %%\LaTeX%%.
- *
- * Copyright %%\copyright%% 1985 by Van Jacobson, Lawrence Berkeley Laboratory
- * This program may be freely used and copied but may not be sold
- * without the author's written permission. This notice must remain
- * in any copy or derivative.
- *
- * This program is an adaptation of "vfontedpr" v4.2 (12/11/84) from
- * the 4.2bsd Unix distribution. Vfontedpr was written by Dave
- * Presotto (based on an earlier program of the same name written by
- * Bill Joy).
- *
- * I would welcome comments, enhancements, bug fixes, etc. Please
- * mail them to:
- * van@@lbl-rtsg.arpa (from arpanet, milnet, csnet, etc.)
- * ..!ucbvax!lbl-csam!van (from Usenet/UUCP)
- *
- * Modifications.
- * --------------
- * 30 Mar 85 Chris & Van Fixed %|\C|% & %|\S|% (comment & string start
- * indicators to really appear at the start of
- * comments & strings. Changes for speeded-up
- * @expmatch()@.
- * 29 Mar 85 Chris Torek (chris@@maryland): Bug fixes for %|~|% and
- * %|^L|% output. Most cpu-time eaters recoded
- * to improve efficiency.
- * 10 Feb 85 Van Written.
- * 8 Oct 87 JSL Modified so as to compile on VMS. On VMS, we
- * don't use a surrounding shell script, so the
- * options are a bit different --- added %|-i|% to
- * make a file to be %|\input|% in a %%\LaTeX%%
- * environment. Changed some of the characters
- * around --- e.g., we always take %|*|% in math
- * mode (to make it centered) so we have to
- * write %|*|% as %|\*|%. Etc.
- * 14 Jan 88 JSL %|-e|% option for embedded code.
- * 22 Jan 88 JSL Bugfix --- program could overrun @pstack@
- * because of an incorrect limit test.
- * Sep 91 George V Reilly Reformated and cleaned up code, including
- * naughtiness with @NULL@. Added %|@|%,
- * %|%%|%, %|%$|%, and %%\tt \%|%% features.
- * Also the %|%<|%, %|%!|%, and %|%#|% features.
- * 24 Apr 93 Fred Walsteijn Ported to Apple Macintosh MPW Shell: @#ifdef MPW@
- * we must disable Unix @popen()@ and @pclose()@, and
- * use %|"}}\n"|% instead of %|"\\^M"|% in @printtab@.
- * Fixed bug in %|printf("\\rhead[...|% too.
- */
-
- #include <stdio.h>
- #include <ctype.h>
-
- #ifdef MPW
- # define popen(command,type) NULL
- # define pclose(stream) (-1)
- #endif
-
- #ifndef vms
- # include <sys/types.h>
- # include <sys/stat.h>
- # include <time.h>
- #else
- # include <types.h>
- # include <stat.h>
- #endif
-
- typedef int boolean;
-
- #define TRUE 1
- #define FALSE 0
-
- #define STANDARD 0
- #define ALTERNATE 1
-
- #define NOTCODE 0 /* the three states of @incode@ */
- #define INITCODE 1
- #define OTHERCODE 2
-
- #define PNAMELEN 80 /* length of a function/procedure name */
- #define PSMAX 20 /* size of procedure name stacking */
-
- #define BUFFERSIZE 4096
-
- #ifndef vms
- # define OKEXIT 0
- # define BADEXIT 1
- # ifndef DEFSFILE
- # define DEFSFILE "/usr/lib/lgrindefs"
- # endif
- #else
- # define OKEXIT 1
- # define BADEXIT 0
- # define DEFSFILE "TEX$INPUTS:lgrindefs.src"
- #endif
-
-
- /* regular expression routines */
-
- char *expmatch(); /* match a string to an expression */
- char *convexp(); /* convert expression to internal form */
-
-
- /* database query routines */
-
- char *tgetstr();
- int tgetent();
- int tgetflag();
-
-
- /* forward declarations */
-
- void setlang();
- void readfile();
- void putScp();
- void putKcp();
- void putVcp();
- void putstr();
- boolean isproc();
- void outchar();
-
-
- /*
- * The state variables
- */
-
- boolean incomm; /* in a comment of the primary type */
- boolean instr; /* in a string constant */
- boolean inchr; /* in a character constant */
- int incode; /* in program text within a comment */
- int latexcode; /* in program text within %%\LaTeX%% */
- int latex_tt; /* in %|\tt|% text within %%\LaTeX%% */
- boolean use_tt; /* use %|\tt|% everywhere */
- boolean do_at; /* pay attention to %|@|%s in %%\LaTeX%% */
- boolean do_tt; /* pay attention to %|||%s in %%\LaTeX%% */
- boolean nokeyw = FALSE; /* no keywords being flagged */
- boolean prccont; /* continue last procedure */
- boolean code_cmnts = TRUE; /* Treat %|@|%, etc specially in comments */
- boolean code_latex = TRUE; /* Treat %|@|%, etc specially in %%\LaTeX%% */
- boolean linehead; /* at beginning of line or after whitespace */
- int lastout; /* (extended) last character to outchar */
- int comtype; /* type of comment */
- int psptr; /* the stack index of the current procedure */
- char pstack[PSMAX][PNAMELEN+1]; /* the procedure name stack */
- int plstack[PSMAX]; /* the procedure nesting level stack */
- int blklevel; /* current nesting level */
- char *fname = ""; /* File being read */
- int lineno; /* Line number in that file */
- char pname[BUFFERSIZE+1]; /* Current procedure name */
-
-
- /*
- * The language specific globals
- */
-
- char *defsfile = DEFSFILE; /* name of language definitions file */
- char language[PNAMELEN]="c"; /* the language indicator */
- char the_buf[BUFFERSIZE+1]; /* general purpose buffer */
- char *buf = the_buf + 1; /* @buf-1@ must be valid */
- char strings[2*BUFFERSIZE]; /* store the keywords */
- char defs[2 * BUFFERSIZE]; /* language definitions from lgrindefs */
- char *l_keywds[BUFFERSIZE/2];/* keyword table address */
- char *l_prcbeg; /* regular expr for procedure begin */
- char *l_combeg; /* regexp introducing a comment */
- char *l_comend; /* regexp ending a comment */
- char *l_acmbeg; /* regexp introducing a comment */
- char *l_acmend; /* regexp ending a comment */
- char *l_blkbeg; /* regexp beginning of a block */
- char *l_blkend; /* regexp ending a block */
- char *l_strbeg; /* regexp starting string constant */
- char *l_strend; /* regexp ending string constant */
- char *l_chrbeg; /* regexp starting character constant */
- char *l_chrend; /* regexp ending character constant */
- char *l_cdebeg; /* regexp starting prog text within comment */
- char s_cdebeg[PNAMELEN+1]; /* actual string corresponding to @l_cdebeg@ */
- char *l_cdeend; /* regexp ending prog text within comment */
- char *l_texbeg; /* regexp starting %%\TeX%% text in comment */
- char *l_texend; /* regexp ending %%\TeX%% text in comment */
- char *l_txmbeg; /* regexp starting %%\TeX%% math in comment */
- char *l_txmend; /* regexp ending %%\TeX%% math in comment */
- char *l_tt_beg; /* regexp starting verbatim text in comment */
- char *l_tt_end; /* regexp ending typewriter text in comment */
- char *l_at; /* regexp for %|@|% in %%\LaTeX%% text */
- char *l_tt; /* regexp for %|||% in %%\LaTeX%% text */
- char *l_pc; /* regexp for %|%|% in %%\LaTeX%% text */
- char l_escape; /* character used to escape characters */
- boolean l_toplex; /* procedures only defined at top lex level */
- boolean l_onecase; /* upper & lower case equivalent */
- boolean embed = FALSE; /* -e seen --- do embedded code */
- boolean code = TRUE; /* Looking at code */
-
-
- /*
- * global variables also used by expmatch
- */
-
- extern boolean _escaped; /* if last character was an escape */
- extern char *_start; /* start of the current string */
-
-
- extern int (*re_strncmp)(); /* function to do string compares */
- extern int strncmp();
- extern int lc_strncmp();
-
-
-
- int
- main(argc, argv)
- int argc;
- char *argv[];
- {
- struct stat stbuf;
- char *p;
- boolean hseen = FALSE; /* -h seen */
- char *hstring; /* header string to use */
- boolean iseen = FALSE; /* -i seen */
- int files_done = 0;
-
- argc = getredirection(argc, argv);
-
- argc--, argv++;
- do {
- register char *cp;
- register int i;
-
- if (argc > 0) {
- if (!strcmp(argv[0], "-h")) {
- hseen = TRUE;
- if (argc == 1) {
- hstring = "";
- argc = 0;
- goto rest;
- }
- hstring = argv[1];
- argc--, argv++;
- argc--, argv++;
- if (argc > 0)
- continue;
- goto rest;
- }
-
- /* take input from the standard place */
- if (!strcmp(argv[0], "-")) {
- argc = 0;
- goto rest;
- }
-
- /* Process embedded text */
- if (!strcmp(argv[0], "-e")) {
- embed = TRUE;
- argc--, argv++;
- continue;
- }
-
- /* format for inclusion */
- if (!strcmp(argv[0], "-i")) {
- iseen = TRUE;
- argc--, argv++;
- continue;
- }
-
- /* indicate no keywords */
- if (!strcmp(argv[0], "-n")) {
- nokeyw++;
- argc--, argv++;
- continue;
- }
-
- /* Don't treat %|@|%, etc. specially in comments */
- if (!strcmp(argv[0], "-c")) {
- code_cmnts = FALSE;
- argc--, argv++;
- continue;
- }
-
- /* Do treat %|@|%, etc. specially in comments */
- if (!strcmp(argv[0], "+c")) {
- code_cmnts = TRUE;
- argc--, argv++;
- continue;
- }
-
- /* Don't treat %|@|%, etc. specially in
- * %%\LaTeX%% text (@embed@ only) */
- if (!strcmp(argv[0], "-a")) {
- code_latex = FALSE;
- argc--, argv++;
- continue;
- }
-
- /* Do treat %|@|%, etc. specially in
- * %%\LaTeX%% text (@embed@ only) */
- if (!strcmp(argv[0], "+a")) {
- code_latex = TRUE;
- argc--, argv++;
- continue;
- }
-
- /* Use %|\tt|% for all fonts */
- if (!strcmp(argv[0], "-t")) {
- use_tt = TRUE;
- argc--, argv++;
- continue;
- }
-
- /* specify the language */
- if (!strncmp(argv[0], "-l", 2)) {
- strcpy(language, argv[0]+2);
- argc--, argv++;
- continue;
- }
-
- /* specify the language description file */
- if (!strncmp(argv[0], "-d", 2)) {
- defsfile = argv[1];
- argc--, argv++;
- argc--, argv++;
- continue;
- }
-
- /* open the file for input */
- if (freopen(argv[0], "r", stdin) == NULL) {
- perror(argv[0]);
- exit(BADEXIT);
- }
-
- fname = argv[0];
- lineno = 0;
- argc--, argv++;
- }
- rest:
-
- if (iseen && embed) {
- fprintf(stderr, "-i makes no sense with -e; -e ignored\n");
- embed = FALSE;
- }
-
- if (!iseen && !embed) {
- if (files_done == 0) {
- printf("\\documentstyle[lgrind,fancyhead]{article}\n");
- printf("\\pagestyle{fancy}\n");
- }
- printf("\\lhead[\\fancyplain{}{\\bf\\thepage}]");
- printf("{\\fancyplain{}{\\bf %s}}\n",
- fname);
- printf("\\rhead[\\fancyplain{}{\\bf %s}]",
- fname);
- printf("{\\fancyplain{}{\\bf\\thepage}}\n");
- printf("\\cfoot{}\n");
- if (files_done == 0) {
- printf("\\begin{document}\n");
- }
- printf("\\begin{lgrind}\n");
- }
-
- if (embed)
- printf("%% This document was generated automagically by lgrind. DO NOT EDIT.\n\n");
- if (iseen)
- printf("%% Remember to use the lgrind style\n\n");
-
- if (hseen) {
- printf("\\Head{");
- putstr(hstring);
- printf("}\n");
- }
-
- setlang();
-
- /* initialize the program */
-
- incomm = instr = inchr = _escaped = FALSE;
- incode = latexcode = latex_tt = NOTCODE;
- do_at = do_tt = TRUE;
- blklevel = 0;
- for (psptr = 0; psptr < PSMAX; psptr++) {
- pstack[psptr][0] = '\0';
- plstack[psptr] = 0;
- }
- psptr = -1;
- fstat(fileno(stdin), &stbuf);
- cp = ctime(&stbuf.st_mtime);
- cp[10] = cp[16] = cp[24] = '\0';
-
- if (!embed) {
- printf("\\File{");
- putstr(fname);
- printf("},{%s},{%s %s}\n", cp+11, cp+4, cp+20);
- }
-
- code = FALSE;
- readfile(stdin);
- files_done++;
-
- if (!iseen && !embed) {
- printf("\\end{lgrind}\n");
- }
-
- if (code)
- fprintf(stderr, "Reached EOF within code in file %s\n", fname);
- } while (argc > 0);
-
- if (!iseen && !embed) {
- printf("\\end{document}\n");
- }
- exit(OKEXIT);
- }
-
-
-
- /*
- * @readfile()@ --- read and process a file
- */
- void
- readfile(fp)
- FILE *fp;
- {
- register char *cp;
- boolean inline = FALSE; /* Doing %( -- %) */
- char term; /* ']' or ')' */
- char *atptr; /* start of %|@|% within %%\LaTeX%% text */
- char *atendptr; /* end of %|@|% within %%\LaTeX%% text */
- char *ttptr; /* start of %|||% within %%\LaTeX%% text */
- char *ttendptr; /* end of %|||% within %%\LaTeX%% text */
- char *pcptr; /* start of %|%|% within %%\LaTeX%% text */
- char *pcendptr; /* end of %|%|% within %%\LaTeX%% text */
- char temp[BUFFERSIZE];
-
- while (fgets(buf, BUFFERSIZE, fp) != NULL) {
- lineno++;
- cp = buf;
- linehead = TRUE;
- lastout = '\0';
- if (embed) {
- if (!code) {
- if (buf[0] == '%' &&
- (buf[1] == '[' || buf[1] == '('
- || buf[1] == '#' || buf[1] == '<' || buf[1] == '!'
- || buf[1] == '@' || buf[1] == '|')) {
-
- for (cp = buf + 2; *cp == ' ' || *cp == '\t'; cp++)
- ;
-
- /* Change the language */
- if (buf[1] == '#') {
- if (*cp == '\n')
- fprintf(stderr, "no language seen after %%#\n");
- else {
- cp[strlen(cp) - 1] = '\0'; /* nuke the @'\n'@ */
- strcpy(language, cp);
- printf("%% switching to %s\n", language);
- setlang();
- }
- continue;
- }
-
- /* Turn %|@|% or %|||% processing within %%\LaTeX%%
- * text on or off. */
-
- if (buf[1] == '@' || buf[1] == '|') {
- if (*cp == '\n')
- fprintf(stderr, "no setting seen after %%%c\n", buf[1]);
- else {
- int flag = (*cp == '1' || *cp == '+');
- if (buf[1] == '@')
- do_at = flag;
- else
- do_tt = flag;
- }
- continue;
- }
-
- code = TRUE;
-
- /* take input from another file or from a shell command */
- if (buf[1] == '<' || buf[1] == '!') {
- FILE *fp;
- char source = buf[1];
-
- cp[strlen(cp) - 1] = '\0'; /* nuke the @'\n'@ */
- if (source == '<')
- fp = fopen(cp, "r");
- else /* @source == '!'@ */
- fp = popen(cp, "r");
-
- if (fp == NULL) {
- sprintf(temp, "%%%c on `%s' failed", source, cp);
- perror(temp);
- } else {
- strcpy(temp, cp);
- printf("%% start of `%s'\n", temp);
- /* printf("\\LGinlinefalse\\LGbegin\\lgrinde\n"); */
- printf("\\begin{lgrind}\n");
- readfile(fp);
- /* printf("\\endlgrinde\\LGend\n"); */
- printf("\\end{lgrind}\n");
- printf("%% end of `%s'\n", temp);
- if (source == '<')
- fclose(fp);
- else
- pclose(fp);
- }
- code = FALSE;
- continue;
- }
-
- /* embedded inline or displayed code */
- if (buf[1] == '(') {
- inline = TRUE;
- term = ')';
- printf("\\LGinlinetrue");
- } else { /* @buf[1] == '['@ */
- inline = FALSE;
- term = ']';
- printf("\\LGinlinefalse");
- }
- if (buf[2] == '\n') {
- printf("\\LGbegin\\lgrinde\n");
- } else {
- buf[strlen(buf)-1] = '\0';
- printf("%s\\lgrinde\n", &buf[2]);
- }
- continue;
-
- } else if (do_at &&
- (atendptr = expmatch(buf, l_at, &atptr,
- (char *) NULL)) != NULL) {
- /* This is a gross hack. Fix it, dammit */
- restart_at:
- pcendptr = expmatch(cp, l_pc, &pcptr, (char *) NULL);
-
- if (pcptr == NULL || atptr < pcptr) {
- putVcp(cp, atptr-1);
- printf("\\LGinlinetrue\\LGbegin\\lgrinde");
- cp = atendptr;
- atendptr = expmatch(cp, l_at, &atptr, (char *) NULL);
- if (atptr != NULL && (pcptr == NULL || atptr < pcptr)) {
- strncpy(temp, cp, atptr-cp);
- temp[atptr-cp] = '\0';
- cp = atendptr;
- printf("\\L{\\LB{");
- putScp(temp);
- printf("}}\\endlgrinde\\LGend{}");
- atendptr = expmatch(cp, l_at, &atptr, (char *) NULL);
- if (atptr != NULL)
- goto restart_at;
- else {
- fputs(cp, stdout); continue;
- }
- } else {
- /* multiline */
- }
- } else {
- fputs(buf, stdout);
- continue;
- }
- } else if (do_tt &&
- (ttendptr = expmatch(buf, l_tt, &ttptr,
- (char *) NULL)) != NULL) {
- pcendptr = expmatch(buf, l_pc, &pcptr, (char *) NULL);
-
- if (pcptr == NULL || ttptr < pcptr) {
- putVcp(buf, ttptr-1);
- } else {
- fputs(buf, stdout); continue;
- }
- } else {
- fputs(buf, stdout);
- continue;
- }
- } /* @if (!code)@ */
-
- /*
- * We're in embedded code.
- */
- if (buf[0] == '%') {
- if (buf[1] == '*') {
- if (term != ']')
- fprintf(stderr, "%%* only makes sense in display mode\n");
- else {
- printf("\\endlgrinde\\LGend\n");
- printf("\\LGinlinefalse\\LGbegin\\lgrinde\n");
- }
- continue;
- } else if (buf[1] == term) {
- if (buf[2] == '\n')
- printf("\\endlgrinde\\LGend\n");
- else
- printf("\\endlgrinde%s", &buf[2]);
- code = FALSE;
- continue;
- } else if (buf[1] == '=') { /* Send literal */
- fputs(&buf[2], stdout);
- continue;
- } else if (buf[1] == '[' || buf[1] == '('
- || buf[1] == ']' || buf[1] == ')') {
- fprintf(stderr,
- "Possible nested embedded code at line %d in %s\n",
- lineno, fname);
- }
- }
-
- /*
- * Inline code --- suppress leading whitespace
- */
- if (inline) {
- while (isspace(*cp))
- cp++;
- }
- } /* @if (embed)@ */
-
- if (*cp == '\f') {
- printf("\\NewPage\n");
- cp++;
- if (*cp == '\n') /* some people like ^Ls on their own line */
- continue;
- }
- prccont = FALSE;
- printf("\\L{\\LB{");
- putScp(cp);
- if (!embed && prccont && (psptr >= 0)) {
- printf("\\ProcCont{");
- putstr(pstack[psptr]);
- printf("}");
- }
- #ifdef DEBUG
- printf("com %o str %o chr %o ptr %d\n", incomm, instr, inchr, psptr);
- #endif
- } /* @while fgets()@ */
- }
-
-
-
- /*
- * Set all of the language-dependent variables
- */
- void
- setlang()
- {
- char *p, *cp;
- int i;
-
- /*
- * get the language definition from the defs file
- */
- i = tgetent(defs, language, defsfile);
- if (i == 0) {
- fprintf(stderr, "no entry for language %s\n", language);
- exit(BADEXIT);
- } else if (i < 0) {
- fprintf(stderr, "cannot find lgrindefs file `%s'\n", defsfile);
- exit(BADEXIT);
- }
-
- p = strings;
- if (tgetstr("kw", &p) == NULL)
- nokeyw = TRUE;
- else {
- char **cpp;
-
- cpp = l_keywds;
- cp = strings;
- while (*cp) {
- while (*cp == ' ' || *cp =='\t')
- *cp++ = '\0';
- if (*cp)
- *cpp++ = cp;
- while (*cp != ' ' && *cp != '\t' && *cp)
- cp++;
- }
- *cpp = NULL;
- }
-
- p = buf; l_prcbeg = convexp(tgetstr("pb", &p));
- p = buf; l_combeg = convexp(tgetstr("cb", &p));
- p = buf; l_comend = convexp(tgetstr("ce", &p));
- p = buf; l_acmbeg = convexp(tgetstr("ab", &p));
- p = buf; l_acmend = convexp(tgetstr("ae", &p));
- p = buf; l_strbeg = convexp(tgetstr("sb", &p));
- p = buf; l_strend = convexp(tgetstr("se", &p));
- p = buf; l_blkbeg = convexp(tgetstr("bb", &p));
- p = buf; l_blkend = convexp(tgetstr("be", &p));
- p = buf; l_chrbeg = convexp(tgetstr("lb", &p));
- p = buf; l_chrend = convexp(tgetstr("le", &p));
- p = s_cdebeg; l_cdebeg = convexp(tgetstr("zb", &p));
- p = buf; l_cdeend = convexp(tgetstr("ze", &p));
- p = buf; l_texbeg = convexp(tgetstr("tb", &p));
- p = buf; l_texend = convexp(tgetstr("te", &p));
- p = buf; l_txmbeg = convexp(tgetstr("mb", &p));
- p = buf; l_txmend = convexp(tgetstr("me", &p));
- p = buf; l_tt_beg = convexp(tgetstr("vb", &p));
- p = buf; l_tt_end = convexp(tgetstr("ve", &p));
-
- l_tt = convexp("\\|");
- l_at = convexp("@");
- l_pc = convexp("%");
-
- l_escape = '\\';
- l_onecase = tgetflag("oc");
-
- re_strncmp = l_onecase ? lc_strncmp : strncmp;
- l_toplex = tgetflag("tl");
- }
-
-
-
- /*
- * Write out a formatted line of program text
- */
- void
- putScp(os)
- char *os;
- {
- register char *s = os; /* pointer to unmatched string */
- register char *s1; /* temp. string */
- char *comptr; /* start of a comment delimiter */
- char *comendptr; /* end of a comment delimiter */
- char *acmptr; /* start of an alt. comment delimiter */
- char *acmendptr; /* end of an alt. comment delimiter */
- char *strptr; /* start of a string delimiter */
- char *strendptr; /* end of a string delimiter */
- char *chrptr; /* start of a char. const delimiter */
- char *chrendptr; /* end of a char. const delimiter */
- char *cdeptr; /* start of prog text delim within a comment */
- char *cdeendptr; /* end of prog text delim within a comment */
- char *cdbptr; /* start of prog text delim within a comment */
- char *cdbendptr; /* end of prog text delim within a comment */
- char *texptr; /* start of %%\TeX%% text delim within a comment */
- char *texendptr; /* end of %%\TeX%% text delim within a comment */
- char *txmptr; /* start of %%\TeX%% math delim within a comment */
- char *txmendptr; /* end of %%\TeX%% math delim within a comment */
- char *tt_ptr; /* start of typewriter delim within a comment */
- char *tt_endptr; /* end of typewriter delim within a comment */
- char *blksptr; /* start of a lexical block start */
- char *blksendptr; /* end of a lexical block start */
- char *blkeptr; /* start of a lexical block end */
- char *blkeendptr; /* end of a lexical block end */
-
- _start = os; /* remember the start for @expmatch()@ */
- _escaped = FALSE;
- if (nokeyw || incomm || instr)
- goto skip;
- if (isproc(s)) {
- printf("\\Proc{");
- putstr(pname);
- printf("}");
- if (!embed && psptr < PSMAX-1) {
- ++psptr;
- strncpy(pstack[psptr], pname, PNAMELEN);
- pstack[psptr][PNAMELEN] = '\0';
- plstack[psptr] = blklevel;
- }
- }
- skip:
- do {
- /* check for string, comment, blockstart, etc */
- if (!incomm && !instr && !inchr) {
-
- blkeendptr = expmatch(s, l_blkend, &blkeptr, (char *) NULL);
- blksendptr = expmatch(s, l_blkbeg, &blksptr, (char *) NULL);
- comendptr = expmatch(s, l_combeg, &comptr, (char *) NULL);
- acmendptr = expmatch(s, l_acmbeg, &acmptr, (char *) NULL);
- strendptr = expmatch(s, l_strbeg, &strptr, (char *) NULL);
- chrendptr = expmatch(s, l_chrbeg, &chrptr, (char *) NULL);
-
- /* check for end of program text in comment */
- if (incode != NOTCODE) {
- cdeendptr = expmatch(s, l_cdeend, &cdeptr, (char *) NULL);
-
- if ((cdeptr == NULL && (comptr != NULL || acmptr != NULL))
- || (cdeptr != NULL
- && ((comptr != NULL && comptr < cdeptr)
- || ((acmptr != NULL && acmptr < cdeptr))))) {
- fprintf(stderr,
- "Comments may not be nested within program text within comments\n");
- s = (comptr != NULL) ? comptr : acmptr;
- incode = NOTCODE;
- continue;
- }
-
- /* look to see if there's a \<zb> in the program text */
- cdbendptr = expmatch(s, l_cdebeg, &cdbptr, (char *) NULL);
- if (cdeptr != NULL
- && (strptr == NULL || cdbptr < strptr)
- && (chrptr == NULL || cdbptr < chrptr)
- && (blksptr == NULL || cdbptr < blksptr)
- && (blkeptr == NULL || cdbptr < blkeptr)) {
- if (cdbptr > s && cdbptr[-1] == l_escape) {
- putKcp(s, cdbptr-2, FALSE);
- printf("\\C{}");
- putKcp(s_cdebeg, s_cdebeg + strlen(s_cdebeg) - 1, TRUE);
- printf("\\CE{}");
- s = cdbendptr;
- incode = OTHERCODE;
- continue;
- }
- }
-
- comendptr =
- expmatch(s, (comtype == STANDARD) ? l_comend : l_acmend,
- &comptr, (char *) NULL);
-
- if ((cdeptr == NULL && comptr != NULL)
- || (cdeptr != NULL && (comptr != NULL && comptr < cdeptr))) {
- fprintf(stderr,
- "Unterminated program text within comment\n");
- printf("\\C{}");
- s = comptr;
- incode = NOTCODE; incomm = TRUE;
- continue;
- }
-
-
- if (cdeendptr != NULL) {
- if ((strptr == NULL || cdeptr < strptr)
- && (chrptr == NULL || cdeptr < chrptr)
- && (blksptr == NULL || cdeptr < blksptr)
- && (blkeptr == NULL || cdeptr < blkeptr)) {
- if (incode == INITCODE && cdeptr == s) {
- printf("\\C{}");
- putKcp(s_cdebeg, s_cdebeg + strlen(s_cdebeg) - 1, TRUE);
- } else {
- putKcp(s, cdeptr-1, FALSE);
- printf("\\C{}");
- }
- s = cdeendptr;
- incode = NOTCODE; incomm = TRUE;
- continue;
- }
- } else if (strptr == NULL && chrptr == NULL
- && blksptr == NULL && blkeptr == NULL) {
- cdeptr = s;
- s += strlen(s);
- putKcp(cdeptr, s-1, FALSE);
- incode = OTHERCODE;
- continue;
- } /* else there is a string/char/block on this line */
-
- incode = OTHERCODE;
- } /* @if (incode)@ */
-
-
- /* start of a comment? */
- if (comptr != NULL
- && (strptr == NULL || comptr < strptr)
- && (acmptr == NULL || comptr < acmptr)
- && (chrptr == NULL || comptr < chrptr)
- && (blksptr == NULL || comptr < blksptr)
- && (blkeptr == NULL || comptr < blkeptr)) {
- putKcp(s, comptr-1, FALSE);
- printf("\\C{}");
- s = comendptr;
- putKcp(comptr, comendptr-1, FALSE);
- incomm = TRUE;
- comtype = STANDARD;
- continue;
- }
-
- /* start of an alternate-form comment? */
- if (acmptr != NULL
- && (strptr == NULL || acmptr < strptr)
- && (chrptr == NULL || acmptr < chrptr)
- && (blksptr == NULL || acmptr < blksptr)
- && (blkeptr == NULL || acmptr < blkeptr)) {
- putKcp(s, acmptr-1, FALSE);
- printf("\\C{}");
- s = acmendptr;
- putKcp(acmptr, acmendptr, FALSE);
- incomm = TRUE;
- comtype = ALTERNATE;
- continue;
- }
-
- /* start of a string? */
- if (strptr != NULL
- && (chrptr == NULL || strptr < chrptr)
- && (blksptr == NULL || strptr < blksptr)
- && (blkeptr == NULL || strptr < blkeptr)) {
- putKcp(s, strptr-1, FALSE);
- printf("\\S{}");
- s = strendptr;
- putKcp(strptr, strendptr-1, FALSE);
- instr = TRUE;
- continue;
- }
-
- /* start of a character string? */
- if (chrptr != NULL
- && (blksptr == NULL || chrptr < blksptr)
- && (blkeptr == NULL || chrptr < blkeptr)) {
- putKcp(s, chrptr-1, FALSE);
- printf("\\S{}");
- s = chrendptr;
- putKcp(chrptr, chrendptr-1, FALSE);
- inchr = TRUE;
- continue;
- }
-
- /* end of a lexical block */
- if (blkeptr != NULL) {
- if (blksptr == NULL || blkeptr < blksptr) {
- putKcp(s, blkeendptr - 1, FALSE);
- s = blkeendptr;
- blklevel--;
- if (psptr >= 0 && plstack[psptr] >= blklevel) {
-
- /* end of current procedure */
- blklevel = plstack[psptr];
-
- /* see if we should print the last proc name */
- if (--psptr >= 0)
- prccont = TRUE;
- else
- psptr = -1;
- }
- continue;
- }
- }
-
- /* start of a lexical block */
- if (blksptr != NULL) {
- putKcp(s, blksendptr - 1, FALSE);
- s = blksendptr;
- blklevel++;
- continue;
- }
-
- /* check for end of comment */
- } else if (incomm) {
-
- cdeendptr = expmatch(s, l_cdebeg, &cdeptr, (char *) NULL);
- texendptr = expmatch(s, l_texbeg, &texptr, (char *) NULL);
- txmendptr = expmatch(s, l_txmbeg, &txmptr, (char *) NULL);
- tt_endptr = expmatch(s, l_tt_beg, &tt_ptr, (char *) NULL);
-
- if (code_cmnts) {
-
- /* Check for program text within comment */
- if (cdeptr != NULL
- && (texptr == NULL || cdeptr < texptr)
- && (tt_ptr == NULL || cdeptr < tt_ptr)
- && (txmptr == NULL || cdeptr < txmptr)) {
- putKcp(s, cdeptr-1, TRUE);
- printf("\\CE{}");
- s = cdeendptr;
- incode = INITCODE; incomm = FALSE;
- continue;
- }
-
- /* Check for %%\TeX%% text within comment */
- if (texptr != NULL
- && (tt_ptr == NULL || texptr < tt_ptr)
- && (txmptr == NULL || texptr < txmptr)) {
- putKcp(s, texptr-1, TRUE);
- s = texendptr;
- if ((texendptr =
- expmatch(s, l_texend, &texptr, (char *) NULL)) != NULL) {
- putchar('{'); putVcp(s, texptr-1); putchar('}');
- s = texendptr;
- } else {
- fprintf(stderr,
- "TeX text within a comment must all be on one line\n");
- s += strlen(s);
- }
- continue;
- }
-
- /* Check for typewriter text within comment */
- if (tt_ptr != NULL
- && (txmptr == NULL || tt_ptr < txmptr)) {
- putKcp(s, tt_ptr-1, TRUE);
- s = tt_endptr;
- if ((tt_endptr =
- expmatch(s, l_tt_end, &tt_ptr, (char *) NULL)) != NULL) {
- printf("{\\tt ");
- putKcp(s, tt_ptr-1, TRUE);
- printf("}");
- s = tt_endptr;
- } else {
- fprintf(stderr,
- "typewriter text within a comment must all be on one line\n\t%s", s);
- s += strlen(s);
- }
- continue;
- }
-
- /* Check for %%\TeX%% math within comment */
- if (txmptr != NULL) {
- putKcp(s, txmptr-1, TRUE);
- s = txmendptr;
- if ((txmendptr =
- expmatch(s, l_txmend, &txmptr, (char *) NULL)) != NULL) {
- putchar('$'); putVcp(s, txmptr-1); putchar('$');
- s = txmendptr;
- } else {
- fprintf(stderr,
- "TeX math within a comment must all be on one line\n");
- s += strlen(s);
- }
- continue;
- }
- } /* @if (code_cmnts)@ */
-
- if ((comendptr =
- expmatch(s, (comtype == STANDARD) ? l_comend : l_acmend,
- (char **) NULL, (char *) NULL)) != NULL) {
- putKcp(s, comendptr-1, TRUE);
- s = comendptr;
- incomm = FALSE;
- printf("\\CE{}");
- } else {
- comptr = s;
- s += strlen(s);
- putKcp(comptr, s-1, TRUE);
- }
- continue;
-
- /* check for end of string */
- } else if (instr) {
- if ((strendptr =
- expmatch(s, l_strend, (char **) NULL, (char *) NULL)) != NULL) {
- putKcp(s, strendptr-1, TRUE);
- s = strendptr;
- instr = FALSE;
- printf("\\SE{}");
- } else {
- strptr = s;
- s += strlen(s);
- putKcp(strptr, s-1, TRUE);
- }
- continue;
-
- /* check for end of character string */
- } else if (inchr) {
- if ((chrendptr =
- expmatch(s, l_chrend, (char **) NULL, (char *) NULL)) != NULL) {
- putKcp(s, chrendptr-1, TRUE);
- s = chrendptr;
- inchr = FALSE;
- printf("\\SE{}");
- } else {
- chrptr = s;
- s += strlen(s);
- putKcp(chrptr, s-1, TRUE);
- }
- continue;
- }
-
- /* print out the line */
- chrptr = s;
- s += strlen(s);
- putKcp(chrptr, s-1, FALSE);
-
- } while (*s);
- }
-
-
-
- /*
- * Output a %%\LaTeX%% command to tab to column "col" (see lgrind.doc
- * for a partial explanation of the bizarre brace arrangement).
- */
- #define tabto(col) printf("}\\Tab{%d}{", col);
-
-
-
- /*
- * @islidchr()@ is @TRUE@ for things that can begin identifiers;
- * @isidchr@ is @TRUE@ of identifier constituents.
- */
- #define islidchr(c)(isalpha(c) || (c) == '_' || (c) == '$')
- #define isidchr(c) (isalnum(c) || (c) == '_' || (c) == '$')
-
-
-
- /*
- * Write out a portion of the line
- */
- void
- putKcp(start, end, nix)
- char *start; /* Start of string to write */
- char *end; /* End of string to write */
- boolean nix; /* Don't look for identifiers, numbers */
- {
- int i, c;
-
- while (start <= end) {
- c = *start++;
- /*
- * take care of nice tab stops
- */
- if (c == '\t') {
- while (start <= end && *start == '\t')
- start++;
- tabto(width(_start, start));
- continue;
- }
-
- /*
- * First split off numbers. We have a rather ad hoc
- * definition: A number is a digit followed by any number
- * of digits or letters, and periods.
- * This produces meaningless parses --- %$.2$% is parsed as %|.|%
- * followed by the number %|2|% --- but should produce decent
- * results for most languages (outside of maybe FORTRAN and DCL).
- */
- if (!nix) {
- if (isdigit(c)) {
- do {
- if (c == 'l')
- printf("$\\ell$");
- else
- outchar(c);
- c = *start++;
- } while (isalnum(c) || c == '.');
- start--;
- continue;
- } else if (c == '#' || islidchr(c)) {
- i = getid(--start);
- if (i > 0)
- printf("\\K{");
- else {
- printf("\\V{");
- i = -i;
- }
- while (--i >= 0) {
- c = *start++;
- outchar(c);
- }
- putchar('}');
- continue;
- }
- }
- outchar(c);
- }
- }
-
-
-
- /*
- * Write out a portion of the line verbatim
- */
- void
- putVcp(start, end)
- char *start; /* Start of string to write */
- char *end; /* End of string to write */
- {
- for ( ; start <= end; start++) {
- putchar(*start);
- }
- }
-
-
-
- /*
- * Calculate the width of a string, including tabs
- */
- int
- width(s, os)
- register char *s, *os;
- {
- register int i = 0, c;
-
- while (s < os) {
- c = *s++;
- if (c == '\t') {
- i = (i + 8) &~ 7;
- continue;
- }
- if (c < ' ')
- i += 2;
- else
- i++;
- }
- return i;
- }
-
-
-
- /*
- * Output a string, escaping special characters
- */
- void
- putstr(cp)
- register char *cp;
- {
- register int c;
-
- if (cp == NULL)
- return;
- while ((c = *cp++) != '\0')
- outchar(c);
- }
-
-
-
- /*
- * The following table converts ASCII characters to a printed
- * representation, taking care of all the %%\LaTeX%% quoting. N.B.: all
- * single-character strings are assumed to be equivalent to the
- * character for that index (i.e., @printtab['c']@ can't be @"f"@).
- * (This is purely for efficiency hacking.)
- *
- * Notes:
- * Some pairs of characters are handled specially within @outchar()@;
- * this table contains no indication when that happens.
- * %|`|% is output as %|{`}|% to avoid various ligatures, such as %|!`|%.
- * The %|''|% and %|--|% (and %|---|%) ligatures are not a problem
- * because those characters are output as macros anyway. Using %|{`}|%
- * is sufficient since nothing we put out will ever be given to the
- * hyphenation algorithms anyway.
- */
-
- char *printtab[256] = {
- "\0x", "\\^A", "\\^B", "\\^C", "\\^D", "\\^E", "\\^F", "\\^G",
- #ifndef MPW
- "\\^H", "\t", "}}\n", "\\^K", "\0x", "\\^M", "\\^N", "\\^O",
- #else
- "\\^H", "\t", "}}\n", "\\^K", "\0x", "}}\n", "\\^N", "\\^O",
- #endif
- "\\^P", "\\^Q", "\\^R", "\\^S", "\\^T", "\\^U", "\\^V", "\\^W",
- "\\^X", "\\^Y", "\\^Z", "\\^[", "\\^\\!","\\^]", "\\^\\^","\\^\\_",
- " ", "!", "\\\"", "\\#", "\\$", "\\%", "\\&", "\\'",
- "(", ")", "\\*", "+", ",", "\\-", ".", "\\1",
- "0", "1", "2", "3", "4", "5", "6", "7",
- "8", "9", ":", ";", "\\<", "=", "\\>", "?",
- "@", "A", "B", "C", "D", "E", "F", "G",
- "H", "I", "J", "K", "L", "M", "N", "O",
- "P", "Q", "R", "S", "T", "U", "V", "W",
- "X", "Y", "Z", "[", "\\2", "]", "\\^", "\\_",
- "{`}", "a", "b", "c", "d", "e", "f", "g",
- "h", "i", "j", "k", "l", "m", "n", "o",
- "p", "q", "r", "s", "t", "u", "v", "w",
- "x", "y", "z", "\\{", "\\|", "\\}", "\\~", "\\^?",
- "\200", "\201", "\202", "\203", "\204", "\205", "\206", "\207",
- "\210", "\211", "\212", "\213", "\214", "\215", "\216", "\217",
- "\220", "\221", "\222", "\223", "\224", "\225", "\226", "\227",
- "\230", "\231", "\232", "\233", "\234", "\235", "\236", "\237",
- "\240", "\241", "\242", "\243", "\244", "\245", "\246", "\247",
- "\250", "\251", "\252", "\253", "\254", "\255", "\256", "\257",
- "\260", "\261", "\262", "\263", "\264", "\265", "\266", "\267",
- "\270", "\271", "\272", "\273", "\274", "\275", "\276", "\277",
- "\300", "\301", "\302", "\303", "\304", "\305", "\306", "\307",
- "\310", "\311", "\312", "\313", "\314", "\315", "\316", "\317",
- "\320", "\321", "\322", "\323", "\324", "\325", "\326", "\327",
- "\330", "\331", "\332", "\333", "\334", "\335", "\336", "\337",
- "\340", "\341", "\342", "\343", "\344", "\345", "\346", "\347",
- "\350", "\351", "\352", "\353", "\354", "\355", "\356", "\357",
- "\360", "\361", "\362", "\363", "\364", "\365", "\366", "\367",
- "\370", "\371", "\372", "\373", "\374", "\375", "\376", "\377",
- };
-
-
-
- #define EMDASH (-1)
- /*
- * Output one character, fixed up as required. Since there is no call-back
- * to tell @outchar()@ to flush what it has stored, it must always produce
- * some output --- it can't simply retain state. This makes certain
- * translations impossible, but we can live without them for now....
- */
- void
- outchar(c)
- int c;
- {
- if ((linehead || !incomm) && c == ' ') {
- putchar('_');
- goto fin;
- }
- linehead = FALSE;
- switch (lastout) {
- case '.':
- case '|':
- if (c == lastout)
- printf("\\,");
- break;
- case ' ':
- #if 0 /* gvr hates this trick */
- if (incomm && c == '-') {
- printf("---");
- c = EMDASH; /* For future cleverness... */
- goto fin;
- }
- #endif
- break;
- case '[':
- if (c == ']')
- printf("\\,");
- break;
- case '-':
- if (c == '>')
- printf("\\!");
- break;
- case '<':
- if (c == '-')
- printf("\\!");
- break;
- }
- if (incomm && c == '-') {
- putchar('-');
- goto fin;
- }
- printtab[c][1] ? printf("%s", printtab[c]) : putchar(c);
- fin:
- lastout = c;
- }
-
-
-
- /*
- * Look for a procedure beginning on this line
- */
- boolean
- isproc(s)
- char *s;
- {
- pname[0] = '\0';
- if ((!l_toplex || blklevel == 0)
- && expmatch(s, l_prcbeg, (char **) NULL, pname) != NULL)
- return TRUE;
- return FALSE;
- }
-
-
-
- /*
- * Get the identifier starting at @s@. It is assumed that @s@ may indeed
- * start an identifier. Value is %$>0$% for a keyword --- the count of
- * characters in the keyword --- and %$<0$% if not a keyword, in which
- * case the value returned is the negative of the number of bytes in
- * the matched identifier.
- *
- * This function checks @nokeyw@ and won't check to see if the
- * identifier found is a keyword if it is @TRUE@.
- */
- int
- getid(s)
- char *s;
- {
- char **ss = l_keywds;
- int i = 1;
- char *cp = s;
- int firstc = *s;
-
- while (++cp, isidchr(*cp))
- i++;
- if (nokeyw)
- return -i;
- while (cp = *ss++) {
- if (!l_onecase && firstc != *cp)
- continue;
- if ((*re_strncmp)(s, cp, i) == 0 && !isidchr(cp[i]))
- return i;
- }
- return -i;
- }
-
-
-
- /*
- * @getredirection()@ is intended to aid in porting C programs
- * to VMS (Vax-11 C) which does not support %|>|% and %|<|%
- * I/O redirection. With suitable modification, it may
- * useful for other portability problems as well.
- *
- * Modified, 24-Jan-86 by Jerry Leichter
- * When creating a new output file, force the maximum record size to
- * 512; otherwise, it ends up as 0 (though the C I/O system won't write
- * a record longer than 512 bytes anyway) which will cause problems if
- * the file is later opened for @APPEND@ --- if the maximum record size
- * is 0, C will use the length of the longest record written to the file
- * for its buffer!
- */
-
- #ifdef vms
- # include <stdio.h>
- # include <errno.h>
-
- int
- getredirection(argc, argv)
- int argc;
- char **argv;
- /*
- * Process VMS redirection args. Exit if any error is seen.
- * If @getredirection()@ processes an argument, it is erased
- * from the vector. @getredirection()@ returns a new @argc@ value.
- *
- * Warning: do not try to simplify the code for VMS. The code
- * presupposes that @getredirection()@ is called before any data is
- * read from @stdin@ or written to @stdout@.
- *
- * Normal usage is as follows:
- *@
- * main(argc, argv)
- * int argc;
- * char *argv[];
- * {
- * argc = getredirection(argc, argv);
- * }@
- */
- {
- register char *ap; /* Argument pointer */
- int i; /* @argv[]@ index */
- int j; /* Output index */
- int file; /* File_descriptor */
-
- for (j = i = 1; i < argc; i++) { /* Do all arguments */
- switch (*(ap = argv[i])) {
- case '<': /* %|<file|% */
- if (freopen(++ap, "r", stdin) == NULL) {
- perror(ap); /* Can't find file */
- exit(errno); /* Is a fatal error */
- }
- break;
-
- case '>': /* %|>file|% or %|>>file|% */
- if (*++ap == '>') { /* %|>>file|% */
- /*
- * If the file exists, and is writable by us,
- * call @freopen()@ to append to the file (using the
- * file's current attributes). Otherwise, create
- * a new file with "vanilla" attributes as if
- * the argument was given as %|>filename|%.
- * @access(name, 2)@ is @TRUE@ if we can write on
- * the specified file.
- */
- if (access(++ap, 2) == 0) {
- if (freopen(ap, "a", stdout) != NULL)
- break; /* Exit @case@ statement */
- perror(ap); /* Error, can't append */
- exit(errno); /* After @access@ test */
- } /* If file accessable */
- }
- /*
- * On VMS, we want to create the file using "standard"
- * record attributes. @create(...)@ creates the file
- * using the caller's default protection mask and
- * "variable length, implied carriage return"
- * attributes. @dup2()@ associates the file with @stdout@.
- */
- if ((file = creat(ap, 0, "rat=cr", "rfm=var", "mrs=512")) == -1
- || dup2(file, fileno(stdout)) == -1) {
- perror(ap); /* Can't create file */
- exit(errno); /* is a fatal error */
- } /* If %|>|% creation */
- break; /* Exit @case@ test */
-
- default:
- argv[j++] = ap; /* Not a redirector */
- break; /* Exit @case@ test */
- }
- } /* For all arguments */
- argv[j] = NULL; /* Terminate @argv[]@ */
- return j; /* Return new @argc@ */
- }
-
- #else /* @!vms@ */
-
- getredirection(argc, argv)
- int argc;
- char *argv[];
- /*
- * Dummy routine.
- */
- {
- return (argv[0], argc);
- }
-
- #endif /* @!vms@ */
-